// GetThis_Client.cpp : Defines the entry point for the console application.
//

#define WIN32_LEAN_AND_MEAN

#include "Common.h"
#include "LogManager.h"
#include "IniManager.h"
#include "ConnectionManager.h"
#include "UpdateManager.h"
#include "VersionHelper.h"
#include <chrono>
#include <future>

#include <io.h>
#include <fcntl.h>
// Try to get the authorization duration.
bool TryGetAuthorization(VersionInformations& versionInformations, Configuration& configuration, bool& restart, double& duration)
{
	ConnectionInformations connectionInformations;
	Authorization authorization;

	// get the connection informations
	LogManager::DisplayMessage(L"Getting the server connection informations ...\n");
	ConnectionManager connectionManager(configuration.ConnectionOptions);
	if (!connectionManager.GetConnectionInformations(connectionInformations)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could not get server connection informations.\n");

	// check for updates
	LogManager::DisplayMessage(L"Checking for updates ...\n");
	if (!UpdateManager::TryUpdateIfMandatory(connectionInformations, versionInformations, restart)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : Could check for updates.\n");

	// if restart is mandatory, restart the application
	if (restart) return true;

	// get the authorization token
	LogManager::DisplayMessage(L"Getting the authorization from the server ...\n");
	if (!connectionManager.GetAuthorization(connectionInformations, authorization)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could not get the authorization from the server.\n");
	switch (authorization.Status)
	{
	case Status::Accepted:
		if (!IniManager::TryUpdateKey(authorization.NewKey, __CONFIGURATION_INI_PATH__)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could not update configuration file (new user key was %s).\n", authorization.NewKey.c_str());
		duration = authorization.Duration;
		return true;
		break;
	case Status::UserNotFound:
		return LogManager::DisplayErrorAndPause(L"Invalid user name. Please review your Configuration.ini file.\n");
	case Status::InvalidKey:
		return LogManager::DisplayErrorAndPause(L"Invalid user Key. Please review your Configuration.ini file.\n");
	case Status::InvalidIp:
		return LogManager::DisplayErrorAndPause(L"Invalid user Ip. Please contact me by mail.\n");
	case Status::None:
	default:
		return LogManager::DisplayErrorAndPause(L"Unexpected error. Please contact me by mail.\n");
	}
}

int __cdecl main(int, TCHAR **)
{
	VersionInformations versionInformations;
	Configuration configuration;
	double duration;
	bool restart;

	// enable UTF-16 on console output
	_setmode(_fileno(stdout), _O_U16TEXT);

	// get the version informations
	if (!VersionHelper::GetVersionInformations(versionInformations)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could get the version informations.\n");
	wcout << CYAN << _W(versionInformations.ProductName) << YELLOW << L" v" << _W(versionInformations.ProductVersion) << LIGHTGREY << L"\n";

	// handle any pending update.
	if (!UpdateManager::HandlePendingUpdate(versionInformations.CurrentExePath, restart)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could not handle pending update.\n");

	// if restart is mandatory, restart the application
	if (restart) return 0;

	do
	{
		// read the configuration file
		LogManager::DisplayMessage(L"Reading the configuration file ...\n");
		if (!IniManager::Read(__CONFIGURATION_INI_PATH__, configuration)) return LogManager::DisplayErrorAndPause(L"Shutdown reason : could not load configuration file.\n");

		// get the autorization duration
		if (!TryGetAuthorization(versionInformations, configuration, restart, duration)) return 1;

		// if restart is mandatory, restart the application
		if (restart) return 0;

		// update the end time
		auto endTime = chrono::system_clock::now() + chrono::duration<double>(duration);

		// start the grabber
		LogManager::DisplayWithSuspense(L"Starting the grabber");
		async(launch::async, GrabManager::Start, configuration.GrabOptions);

		while (chrono::system_clock::now() < endTime)
			Sleep(__CHECK_CONNECTION_INTERVAL__);

		LogManager::DisplayWithSuspense(L"Authorization expired");
		GrabManager::Stop();
	} while (true);
	return 0;
}